package resourcePool

import (
	"bytes"
	"encoding/binary"
	"encoding/json"
	"fmt"
	"gitee.com/dongmingchao/decent-ft/src/JSlike"
	"gitee.com/dongmingchao/decent-ft/src/utils"
	"io"
	"log"
	"strings"
)

type GTree struct {
	Version   uint32
	FileCount uint32
	Files     FilePointers
	Checksum  [20]byte
	Neighbors []GNeighbor
}

func (t GTree) BeforeMarshal() JSlike.Object {
	return JSlike.Object{
		"Version":   t.Version,
		"FileCount": t.FileCount,
		"Files":     t.Files,
		"Checksum":  fmt.Sprintf("%x", t.Checksum),
		"Neighbors": t.Neighbors,
	}
}

func (t GTree) MarshalJSON() ([]byte, error) {
	return json.Marshal(t.BeforeMarshal())
}

func (t GTree) String() string {
	s, err := json.MarshalIndent(t, "", "  ")
	if err != nil {
		log.Fatal(err)
	}
	return string(s)
}

func (t *GTree) Write(w io.Writer) {
	binary.Write(w, binary.BigEndian, t.Version)
	binary.Write(w, binary.BigEndian, t.FileCount)
	for _, each := range t.Files {
		each.Write(w)
	}
	binary.Write(w, binary.BigEndian, t.Checksum)
}

func (t *GTree) Read(r io.Reader) {
	binary.Read(r, binary.BigEndian, &t.Version)
	binary.Read(r, binary.BigEndian, &t.FileCount)
	t.Files = make([]*GFile, t.FileCount)
	for i := uint32(0); i < t.FileCount; i++ {
		t.Files[i] = &GFile{}
		t.Files[i].Read(r)
	}
	binary.Read(r, binary.BigEndian, &t.Checksum)
}

func (t *GTree) SearchFileHash(nameOrHashPrefix string) []string {
	var resHashes []string
	for _, f := range t.Files {
		mark := fmt.Sprintf("%x", f.Checksum)
		if strings.HasPrefix(mark, nameOrHashPrefix) || strings.HasPrefix(f.FileName, nameOrHashPrefix) {
			resHashes = append(resHashes, mark)
		}
	}
	return resHashes
}

func (t *GTree) SearchFile(nameOrHashPrefix string) []GFile {
	var ret []GFile
	for _, f := range t.Files {
		mark := fmt.Sprintf("%x", f.Checksum)
		if strings.HasPrefix(mark, nameOrHashPrefix) || strings.HasPrefix(f.FileName, nameOrHashPrefix) {
			ret = append(ret, *f)
		}
	}
	return ret
}

func (t *GTree) SearchFileByNameExactly(filename string) *GFile {
	for _, f := range t.Files {
		fmt.Println("searching", filename, f.FileName, filename == f.FileName)
		if filename == f.FileName {
			return f
		}
	}
	return nil
}

func (t *GTree) UpdateFileCount() {
	t.FileCount = uint32(len(t.Files))
}

func (t *GTree) UpdateChecksum() {
	// 根据版本号和文件数量生成资源池token
	var allBytes bytes.Buffer
	allBytes.Write(utils.UInt32ToBytes(t.Version))
	allBytes.Write(utils.UInt32ToBytes(t.FileCount))
	// 没有内容
	binary.Write(&allBytes, binary.BigEndian, t.Files)
	fmt.Println("tree hash body", allBytes.Bytes())
	t.Checksum = Sha1CheckSum(allBytes.Bytes())
}

/*
写入的Neighbors信息不包含Files
*/
func (t *GTree) WriteSummary(w io.Writer) {
	binary.Write(w, binary.BigEndian, t.Version)
	binary.Write(w, binary.BigEndian, t.FileCount)
	for _, each := range t.Files {
		each.Write(w)
	}
	binary.Write(w, binary.BigEndian, t.Checksum)
}
